<html>
    <head>
        <title>处理边界情况</title>
    </head>
    <body>
        <script>
            // 处理边界情况     
                    /*
                        这里记录的都是和处理边界情况有关的功能，即一些需要对Vue的规则做一些小调整的特殊情况。
                        不过注意这些功能都是有劣势或危险的场景的。
                        我们就会再每个案例中注明，所以当你使用每个功能的时候请稍加留意。
                    */

                    // 一、 访问元素 & 组件
                                /*
                                    在绝大多数情况下，我们最好不要触达另一个组件实例内部或手动操作DOM。
                                    不过，也确实在一些情况下做这些事情是合适的。
                                */

                                // 1、访问 "根实例"
                                        /*
                                            在每个new Vue 实例的子组件中，其根实例可以通过 $root 实例属性访问到。
                                        */
                                        //  例如，在这个根实例中：
                                              new Vue({
                                                    data:{
                                                        foo:1
                                                    },
                                                    computed:{
                                                        bar:function(){
                                                            /* .... */
                                                        }
                                                    },
                                                    methods:{
                                                        baz:function(){
                                                            /*....*/
                                                        }
                                                    }
                                              });

                                        // 所有的子组件都可以将这个示例作为一个全局 store 来"访问" 或 "使用"：

                                            // 获取根组件(根实例)的数据
                                            this.$root.foo

                                            // 写入根组件(根实例)的数据
                                            this.$root.foo =2

                                            // 访问根组件(根实例)的计算属性
                                            this.$root.bar

                                            // 调用根组件(根实例)的方法
                                            this.$root.baz()

                                         /*
                                              注意：  
                                                   对于 demo 或 非常小型的"有少量组件的应用" 来说这是很方便的。
                                                   不过，这个模式扩展到中大型应用来说就不然了。
                                                   因此，在绝大多数情况下，我们强烈推荐使用 Vuex 来管理应用的状态。
                                         */


                                // 2、访问父组件实例
                                        /*
                                            和 $root 类似， $parent 属性可以用来从一个子组件访问父组件的实例。
                                            它提供了一种机会，可以在后期随时触达父级组件，以替代将数据以 prop 的方式传入组件的方式。       
                                        */
                                        /*
                                            注意：
                                                在绝大多数情况下，触达父级组件会使得你的应用更加难以调试和理解，尤其是当你变更了腹肌组件的数据的时候。
                                                当我们稍后回看那个组件的时候，很难找出那个变更是从哪里发起的。
                                        */
                                        /*
                                            另外，在一些可能适当的时候，你需要特别地共享一些组件库。
                                            举个例子，在和JavaScript API 进行交互而你不渲染HTML的抽象组件内，诸如这些假设性的Google地图组件一样：

                                                <google-map>
                                                    <google-map-markers v-bind:place="iceCreamShops"></google-map-markers>
                                                </google-map>

                                            这个 <google-map> 组件可以定义一个 map 属性，所有的子组件都需要访问它。
                                            在这种情况下 <google-map-markers> 可能想要通过 this.$parent.map 的方式来访问那个地图，以便围棋添加一组标记。


                                            请留意，尽管如此，通过这种模式构建出来的那个组件的内部仍然是容易出现问题的。
                                            比如，谁想一下我们添加一个新的 <google-map-marker> 组件，当 <google-map-markers>在其内部出现的时候，只会渲染那个区域内的标记：

                                                <google-map>
                                                    <google-map-region v-bind:shape="cityBoundaries">
                                                        <google-map-markers v-bind:place="iceCreamShops"></google-map-markers>
                                                    </google-map-region>
                                                </google-map>

                                            那么在<google-map-markers>内部你可能发现自己需要一些类似这样的hack:

                                                var map = this.$parent.map || this.$parent.$parent.map

                                            很快它就会失控。这也是我们针对需要向任意更深层级的组件提供上下文信息时推荐"依赖注入" 的原因
                                        */


                                // 3、访问子组件实例或子元素
                                        /*
                                            尽管存在 prop 和 事件，有的时候你仍可能需要在JavaScript 里直接访问一个子组件。
                                            为了达到这个目的，你可以通过 ref 这个 atrribute (标签属性) 为组件赋予一个引用ID .

                                                 例如：
                                                         <base-input ref="usernameInput"></base-input>

                                            现在在你已经定义了ref的组件里，你可以使用：
                                                         （在<base-input>组件的父级组件中）：

                                                         this.$refs.usernameInput

                                            来访问这个<base-input> 实例，以便不时之需。 比如程序化地从一个父组件聚焦到这个输入框。
                                            在刚才那个例子中，该 <base-input>组件也可以使用一个类似的 ref attribute 来提供对<base-input>内部子元素的访问：
                                                例如：
                                                       ----在 <base-input> 组件的模板中----
                                                        <input ref="input">    
                                                        // 注意：  此引用是挂在<base-input>组件实例上的  (为组件声明的引用，总是挂在父级组件的实例上)
                                        */
                                         // 设置你可以在<base-input>组件中定义方法：
                                                // 在<base-input>组件声明中：
                                                methods:{
                                                    // 用来从父组件聚焦到ref="input"
                                                    focus:function(){
                                                        this.$refs.input.focus();
                                                    }
                                                }
                                         // 这样就允许你在<base-input>组件的父级组件中，通过下面代码聚焦 <base-input>中 ref="input"的输入框：
                                                this.$refs.usernameInput.focus();

                                         // 当 ref 和 v-for 一起使用的时候，你得到的 ref 将会是一个 "包含了对应数据源的这些子组件的数组"

                                         /*
                                            注意：
                                                $refs 只会在组件渲染完成之后生效，并且他们不是响应式的。
                                                这仅仅作为一个用来直接操作子组件的"逃生舱"----你应该"避免在模板"或"计算属性"中访问 $refs.
                                         */

                                // 4、依赖注入
                                         /*
                                             在此之前，我们在描述 "访问父组件实例" 的时候，展示给一个类似这样的例子：

                                                    <google-map>
                                                        <google-map-region v-bind:shape="cityBoundaries">
                                                            <google-map-markers v-bind:place="iceCreamShops"></google-map-markers>
                                                        </google-map-region>
                                                    </google-map>


                                             在这个组件里，所有<google-map> 的后代都需要访问一个 getMap 方法，以便知道要跟哪个地图进行交互。
                                             不幸的是，使用 $parent 属性无法很好的扩展到更深层级的嵌套组件上。
                                             这也是依赖注入的用武之地，它用到了两个新的实例选项:  "provide" 和 "inject"
                                         */
                                          
                                         /*
                                             provide 选项允许我们指定我们想要提供给都带组件的 数据/方法。
                                             在这个例子中，我们想要给所有后代组件提供一个名为"getMap"的方法，以便他们可以访问到那个地图：
                                         */
                                                provide:function(){   // provide 选项是一个对象，它提供了我们想要提供给后代组件的数据/方法。
                                                    return {
                                                        getMap:this.getMap
                                                    }
                                                }

                                        // 然后再任何后代组件里，我们都可以使用inject 选项来接收指定的我们想要添加在这后代组件实例上的属性(propperty)
                                                inject:['getMap']

                                        /*
                                            你可以在"官网教程与本处对应的位置"看到完整的示例。
                                            相比 $parent 来说，这个用法可以让我们在"任意后代组件"中访问"getMap"方法，而不需要暴露真个<google-map>组件实例。
                                            这允许我们更好的持续研发该组件，而不需要担心我们可能会改变/移除一些子组件依赖的东西。
                                            同时，这些组件之间的接口是始终明确定义的，就和 props 一样。


                                            实际上，你可以把依赖注入看作一部分"大范围有效的prop"，除了：
                                                 ①、祖先组件不需要知道哪些后代使用了它提供的 property
                                                 ②、后代组件不需要知道被注入的 property 是来自哪里。
                                        */

                                        /*
                                            然而，依赖注入还是有负面影响的。
                                            它将你应用程序中的组件与它们当前的组织方式耦合在一起了，是重构变得更加困难。
                                            同时所提供的 property 是"非响应式"的。
                                            这是出于设计的考虑，因为使用它们来创建一个中心化规模化的数据跟使用 $root 做这件事都是不够好的。
                                            如果你想要共享的这个propery 是你的应用特有的，而不是通用化的，或者如果你想在祖先组件中更新所提供的数据，
                                            那么这意味着你可能需要换用一个像Vuex 这样的"状态管理方案"了。
                                        */

                                                

                                        
        </script>
    </body>
</html>